package client.container;

import java.util.Arrays;
import java.util.concurrent.PriorityBlockingQueue;

import javax.swing.event.EventListenerList;

import client.event.BtPortContainerListener;
import client.event.BtPortEvent;


/**
 * Una istanza della classe BtPortContainer rappresenta un contenitore 
 * delle porte bluetooth disponibili per ricevere flussi dati e di 
 * controllo. Le porte sono rappresentate come stringhe di quattro
 * caratteri numerici del tipo 4099. Sono ammesse solo porte dispari.
 * Tre le porte 4099 e 409D manca la 409B perchè viene usata per il
 * canale di controllo associato al canale dati della porta 4099.
 * Siccome il contenitore è unico per tutti i componenti 
 * dell'applicazione viene usata una implementazione con 
 * Pattern Singleton, fornendo a tutti gli utilizzatori una sola 
 * istanza della classe.
 */
public class BtPortContainer 

{
	/**
	 * Lista dei listener registrati agli eventi di tipo BtPortEvent.
	 */
	private EventListenerList _eventListenerList = null; 

	/**
	 * Coda che contiene le porte disponibili.
	 */
	private PriorityBlockingQueue<String> _btPsmQueueAvailable = null;

	/**
	 * Riferimento all'unica istanza del Singleton
	 */
	private static BtPortContainer _instance = null;



	private BtPortContainer() 
	{
		/**
		 * Inserisco i valori dell'array in una coda da utilizzare per 
		 * trovare la prima porta psm da spedire al prossimo Gateway
		 */
		_btPsmQueueAvailable = new PriorityBlockingQueue<String>();
		_btPsmQueueAvailable.addAll(Arrays.asList(
				new String[]{"4099", "409D","40A1", "40A7", "40AB", "40AF",
						"40B3", "40B7", "40BB", "40BF", "40C3", "40C7", 
						"40CB", "40CF", "40D3"}));

		/**
		 * Instanzio la lista dei listener che si 
		 * registreranno agli eventi.
		 */
		_eventListenerList = new EventListenerList();

	}

	public String[] getAllBtPort() 
	{
		return _btPsmQueueAvailable.toArray(new String[1]);
	}

	/**
	 * Aggiunto per la rimozione di una porta passata
	 * come parametro.
	 * @param btPort
	 * @return true se la porta è stata rimossa con 
	 * successo, false altrimenti.
	 */
	public boolean extractBtPsm( String btPort) 
	{
		boolean btPortExtracted = _btPsmQueueAvailable.remove(btPort);

		/*
		 * Scatena l'evento che informa i listener del cambiamento 
		 * delle porte disponibili. 
		 */
		if(btPortExtracted == true)
		{
			fireBtPortChanged();
		}

		return btPortExtracted;
	}


	public void insertBtPsm(String psmAvailable) 
	{
		_btPsmQueueAvailable.offer(psmAvailable);

		/*
		 * Scatena l'evento che informa i listener 
		 * del cambiamento delle porte disponibili. 
		 */
		fireBtPortChanged();

	}

	/**
	 * Metodo pubblico statico usato per ottenere 
	 * l'unica instanza del Singleton.
	 */
	public static BtPortContainer getInstance()
	{
		if(_instance == null)
		{
			_instance = new BtPortContainer();
		}

		return _instance;
	}


	/**
	 * Metodi che permettono ai listener di registrarsi per intercettare
	 * gli eventi di cambiamento delle porte.
	 */
	public void addBtPortEventListener(BtPortContainerListener listener)
	{
		_eventListenerList.add(BtPortContainerListener.class, listener);
	}

	public void removeBtPortEventListener(BtPortContainerListener listener)
	{
		_eventListenerList.remove(BtPortContainerListener.class, listener);
	}


	private void fireBtPortChanged()
	{
		/**
		 * lancia l'evento che indica il cambiamento delle porte.
		 * L'oggetto BtPortEvent contiene un riferimento alla sorgente
		 *  ossia this e un array di stringhe, ossia le porte disponibili.
		 */
		BtPortEvent btPortEvent = 
			new BtPortEvent(this, _btPsmQueueAvailable.toArray(new String[1]));

		/**
		 * Per ogni listener che si è precedentemente registrato all'evento
		 * invoco il metodo btPortUpdate passando come parametro 
		 * l'oggetto BtPortEvent.
		 */
		Object[] listenersArray = _eventListenerList.getListenerList();

		for(int i = listenersArray.length - 2; i >= 0; i = i - 2)
		{
			if(listenersArray[i] == BtPortContainerListener.class)
			{
				((BtPortContainerListener)listenersArray[i+1])
				.btPortUpdate(btPortEvent);
			} 
		}

	}

}


